package cqrtplm.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hustcad.plm.pdm.constraint.model.dto.TyplmConstraintQueryDTO;
import com.hustcad.plm.pdm.constraint.model.dto.TyplmConstraintRuleDefQueryDTO;
import com.hustcad.plm.pdm.constraint.model.dto.TyplmCreateConstraintDTO;
import com.hustcad.plm.pdm.constraint.model.vo.TyplmConstraintEditVO;
import com.hustcad.plm.pdm.constraint.model.vo.TyplmConstraintRuleDefVO;
import com.hustcad.plm.pdm.constraint.service.TyplmConstraintExtService;
import com.hustcad.plm.pdm.enumeration.model.dto.EnumerationInputDTO;
import com.hustcad.plm.pdm.enumeration.model.dto.EnumerationValueDTO;
import com.hustcad.plm.pdm.enumeration.model.dto.HandleEnumItemDTO;
import com.hustcad.plm.pdm.enumeration.model.vo.EnumerationItemHandleVO;
import com.hustcad.plm.pdm.enumeration.service.TyplmEnumerationItemService;
import com.hustcad.plm.pdm.enumeration.service.TyplmEnumerationService;
import com.hustcad.plm.pdm.type.service.TyplmTypeService;
import com.ty.basic.constant.TableTypeConstrant;
import com.ty.basic.entity.IdentifierEntity;
import com.ty.basic.entity.enumeration.EnumerationDefDO;
import com.ty.basic.entity.enumeration.EnumerationGroupDO;
import com.ty.basic.exception.message.SystemErrorCodeEnum;
import com.ty.basic.utils.excel.converter.ExcelToList;
import com.ty.basic.vo.TyAttributeDefMapVO;
import cqrtplm.constant.RTErrorCodeEnum;
import cqrtplm.dto.CreateChildEnumDTO;
import cqrtplm.dto.EnumTreeNodeDTO;
import cqrtplm.dto.ImportEnumDTO;
import cqrtplm.entity.TyEnumerationdefDO;
import cqrtplm.mapper.ProcessNumberMapper;
import cqrtplm.mapper.RTEnumMapper;
import cqrtplm.mapper.TyEnumerationdefMapper;
import cqrtplm.service.TyEnumerationdefService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.ty.basic.utils.excel.converter.ExcelToList.getWorkbook;

/**
* @author 博
* @description 针对表【ty_enumerationdef】的数据库操作Service实现
* @createDate 2025-06-05 19:47:06
*/
@Slf4j
@Service
public class TyEnumerationdefServiceImpl extends ServiceImpl<TyEnumerationdefMapper, TyEnumerationdefDO>
    implements TyEnumerationdefService{

    @Resource
    private TyEnumerationdefMapper tyEnumerationdefMapper;
    @Resource
    private TyplmEnumerationService typlmEnumerationService;
    @Resource
    private RTEnumMapper rtEnumMapper;
    @Resource
    private TyplmConstraintExtService typlmConstraintExtService;
    @Resource
    private TyplmEnumerationItemService typlmEnumerationItemService;
    @Resource
    private TyplmTypeService typlmTypeService;
    @Resource
    private ProcessNumberMapper processNumberMapper;

    @Override
    public TyEnumerationdefDO selectByOid(BigInteger defoid) {
        return tyEnumerationdefMapper.selectByOid(defoid);
    }

    @Override
    public String selectDisplayNameByOid(BigInteger defoid) {
        return tyEnumerationdefMapper.selectDisplayNameByOid(defoid);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchImportEnum(MultipartFile file) {
        Map<String, String> fieldMap = ExcelToList.getExcelPropertySettingMapByClass(ImportEnumDTO.class);
        Workbook workbook = getWorkbook(file);
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            Sheet sheet = workbook.getSheetAt(i);
            for (Row row : sheet) {
                for (Cell cell : row) {
                    cell.setCellType(CellType.STRING);
                }
            }
        }
        List<ImportEnumDTO> importEnumDTOS = ExcelToList.excelToList(0, 0, workbook, ImportEnumDTO.class, fieldMap);
        List<ImportEnumDTO> filteredList = importEnumDTOS.stream().filter(ImportEnumDTO::isRowEmpty).collect(
                Collectors.toList());
        if (CollUtil.isEmpty(filteredList)) {
            throw SystemErrorCodeEnum.EXCEL_READ_EXCEPTION.getException("Excel文件");
        }
        List<EnumTreeNodeDTO> enumTreeNodeDTOS = EnumTreeNodeDTO.buildTree(filteredList);
        for (EnumTreeNodeDTO enumTreeNodeDTO : enumTreeNodeDTOS) {
            //创建一级枚举枚举分组
            ImportEnumDTO data = enumTreeNodeDTO.getData();
            EnumerationGroupDO enumerationGroupDO = createEnumGroup(data,new BigInteger("2"));
            for (EnumTreeNodeDTO child : enumTreeNodeDTO.getChildren()) {
                //创建二级枚举分组
                EnumerationGroupDO enumGroup = createEnumGroup(child.getData(), enumerationGroupDO.getOid());
                for (EnumTreeNodeDTO childChild : child.getChildren()) {
                    //创建三级枚举定义器
                    EnumerationDefDO enumerationDefDO = createEnumDef(childChild.getData(), enumGroup.getOid());
                    //创建枚举项
                    List<EnumTreeNodeDTO> children = childChild.getChildren();
                    List<ImportEnumDTO> importEnumDTOList = children.stream().map(EnumTreeNodeDTO::getData).collect(Collectors.toList());
                    createEnumItemList(importEnumDTOList, enumerationDefDO.getOid());
                }
            }
        }

    }

    private void createEnumItemList(List<ImportEnumDTO> importEnumDTOList, BigInteger parentID) {
        HandleEnumItemDTO handleEnumItemDTO = new HandleEnumItemDTO();
        List<EnumerationItemHandleVO> enumItemList = new ArrayList<>();
        for (ImportEnumDTO importEnumDTO : importEnumDTOList) {
            EnumerationItemHandleVO enumItemHandleVO = new EnumerationItemHandleVO();
            enumItemHandleVO.setDisplayName(importEnumDTO.getEnumValue());
            enumItemHandleVO.setDisplayNameCn(importEnumDTO.getEnumValue());
            enumItemHandleVO.setName(importEnumDTO.getEnumID());
            enumItemHandleVO.setDescription(importEnumDTO.getEnumType());
            enumItemHandleVO.setState("0".equals(importEnumDTO.getIsDeactivated()) ? "true" : "false");
            enumItemHandleVO.setName(importEnumDTO.getEnumID());
            enumItemHandleVO.setInternalName(importEnumDTO.getEnumID());
            enumItemList.add(enumItemHandleVO);
        }
        handleEnumItemDTO.setDefoid(parentID);
        handleEnumItemDTO.setEnumItemList(enumItemList);
        typlmEnumerationService.handleEnumItemList(handleEnumItemDTO);
    }

    private EnumerationDefDO createEnumDef(ImportEnumDTO data, BigInteger parentNode) {
        EnumerationInputDTO inputDTO = new EnumerationInputDTO();
        inputDTO.setDisplayName(data.getEnumValue());
        inputDTO.setName(data.getEnumID());
        inputDTO.setParentNodeOid(parentNode);
        inputDTO.setParentNodeOtype(TableTypeConstrant.TY_ENUMERATIONGROUP_OTYPE);
        inputDTO.setIscolored(1);
        return typlmEnumerationService.createEnumDef(inputDTO);
    }

    private EnumerationGroupDO createEnumGroup(ImportEnumDTO importEnumDTO, BigInteger parentNode) {
        EnumerationInputDTO inputDTO = new EnumerationInputDTO();
        inputDTO.setDisplayName(importEnumDTO.getEnumValue());
        inputDTO.setName(importEnumDTO.getEnumID());
        inputDTO.setParentNodeOid(parentNode);
        inputDTO.setParentNodeOtype(TableTypeConstrant.TY_ENUMERATIONGROUP_OTYPE);
        inputDTO.setSystem(0);
        return typlmEnumerationService.createEnumGroup(inputDTO);
    }

    @Override
    public List<TyEnumerationdefDO> selectEnumByName(String name, String description) {
        return tyEnumerationdefMapper.selectEnumByName(name,description);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public EnumerationDefDO createChildEnum(CreateChildEnumDTO dto) {
        List<EnumerationItemHandleVO> itemList = dto.getItemList();
        List<String> collect = itemList.stream().map(EnumerationItemHandleVO::getName).sorted().collect(Collectors.toList());
        String description = String.join("", collect);
        List<EnumerationDefDO> enumDefs = rtEnumMapper.getEnumByDescription(description);
        EnumerationDefDO enumDef;
        if (ObjectUtil.isEmpty(enumDefs)) {
            EnumerationInputDTO inputDTO = new EnumerationInputDTO();
            inputDTO.setDisplayName(dto.getAttributeValue());
            inputDTO.setName(dto.getEnumOid() + "|" +System.currentTimeMillis());
            inputDTO.setParentNodeOid(new BigInteger(rtEnumMapper.getEnumGroupOidByName("childEnum")));
            inputDTO.setParentNodeOtype(TableTypeConstrant.TY_ENUMERATIONGROUP_OTYPE);
            inputDTO.setIscolored(1);
            enumDef = typlmEnumerationService.createEnumDef(inputDTO);
            HandleEnumItemDTO handleEnumItemDTO = new HandleEnumItemDTO();
            handleEnumItemDTO.setDefoid(enumDef.getOid());
            handleEnumItemDTO.setEnumItemList(itemList);
            typlmEnumerationService.handleEnumItemList(handleEnumItemDTO);
        } else {
            enumDef = enumDefs.get(0);
        }
        JSONObject select = rtEnumMapper.select(dto.getAttributeLinkOid());
        if(ObjectUtil.isNotEmpty(select)){
            rtEnumMapper.delete(dto.getAttributeLinkOid());
        }
        rtEnumMapper.insertEnumDescription(String.valueOf(enumDef.getOid()),description,dto.getAttributeLinkOid(),dto.getEnumOid());

        TyplmConstraintQueryDTO constraintQueryDTO = new TyplmConstraintQueryDTO();
        constraintQueryDTO.setAttributereferenceoid(new BigInteger(dto.getAttributeLinkOid()));
        constraintQueryDTO.setAttributereferenceotype(dto.getAttributeLinkOtype());
        //存在枚举 删除
        List<TyplmConstraintEditVO> constraintEditVOS = this.typlmConstraintExtService.getEntityConstraint(
                Collections.singletonList(constraintQueryDTO));
        if (CollUtil.isNotEmpty(constraintEditVOS)) {
            List<TyplmConstraintEditVO> constraintEditVOList = constraintEditVOS.stream().filter(
                    typlmConstraintEditVO -> typlmConstraintEditVO.getKey().equals("EnumDiscreteSetConstraint")).collect(
                    Collectors.toList());

            if(CollUtil.isNotEmpty(constraintEditVOList)){
                for (TyplmConstraintEditVO typlmConstraintEditVO : constraintEditVOList) {
                    this.typlmConstraintExtService.deleteConstraint(typlmConstraintEditVO);
                }
            }
        }

        TyplmConstraintRuleDefQueryDTO queryDTO = new TyplmConstraintRuleDefQueryDTO();
        queryDTO.setOid(new BigInteger(dto.getAttributeLinkOid()));
        queryDTO.setOtype(dto.getAttributeLinkOtype());
        List<TyplmConstraintRuleDefVO> constraintRuleDefVOS = this.typlmConstraintExtService.getConstraintRuleDefByEntity(queryDTO);
        List<TyplmConstraintRuleDefVO> enumDiscreteSetConstraint = constraintRuleDefVOS.stream().filter(
                typlmConstraintRuleDefVO -> typlmConstraintRuleDefVO.getKey()
                        .equals("EnumDiscreteSetConstraint")).collect(Collectors.toList());

        if(CollUtil.isNotEmpty(enumDiscreteSetConstraint)){
            TyplmCreateConstraintDTO createConstraintDTO = new TyplmCreateConstraintDTO();
            createConstraintDTO.setRuleReferenceOid(new BigInteger(dto.getClassOid()));
            createConstraintDTO.setRuleReferenceOtype(TableTypeConstrant.TY_CLASSIFICATION_OTYPE);
            createConstraintDTO.setEntity(new IdentifierEntity(new BigInteger(dto.getAttributeLinkOid()), dto.getAttributeLinkOtype()));
            createConstraintDTO.setConstraintRuleDefVOS(enumDiscreteSetConstraint);
            List<TyplmConstraintEditVO> entityConstraint = this.typlmConstraintExtService.createEntityConstraint(
                    createConstraintDTO);
            //设置属性配枚举
            TyplmConstraintEditVO typlmConstraintEditVO = entityConstraint.get(0);
            typlmConstraintEditVO.setEnumoid(String.valueOf(enumDef.getOid()));
            typlmConstraintEditVO.setEnumotype(TableTypeConstrant.TY_ENUMERATIONDEF_OTYPE);

            typlmConstraintExtService.batchUpdateEntityConstraint(entityConstraint);
        }
        return enumDef;
    }

    @Override
    public Object getTYEnumByOid(String defoid) {
        JSONObject enumObj = rtEnumMapper.select(defoid);
        if(ObjectUtil.isEmpty(enumObj)){
            return new ArrayList<>();
        }
        String childEnumOid = enumObj.getString("ENUMOID");
        String parentEnumOid = enumObj.getString("PARENTENUMOID");
        List<EnumerationItemHandleVO> childEnumerationItemHandleVOS = typlmEnumerationItemService.queryEnumerationItemByDefOid(
                new IdentifierEntity(new BigInteger(childEnumOid), TableTypeConstrant.TY_ENUMERATIONDEF_OTYPE));
        List<EnumerationItemHandleVO> bigEnumerationItemHandleVOS = typlmEnumerationItemService.queryEnumerationItemByDefOid(
                new IdentifierEntity(new BigInteger(parentEnumOid), TableTypeConstrant.TY_ENUMERATIONDEF_OTYPE));
        List<String> childNameList = childEnumerationItemHandleVOS.stream().map(EnumerationItemHandleVO::getName).collect(Collectors.toList());
        for (EnumerationItemHandleVO bigEnumerationItemHandleVO : bigEnumerationItemHandleVOS) {
            if(childNameList.contains(bigEnumerationItemHandleVO.getName())){
                bigEnumerationItemHandleVO.setStateName("true");
            }
        }
        JSONObject result = new JSONObject();
        result.put("enumList",bigEnumerationItemHandleVOS);
        result.put("enumId",parentEnumOid);
        return result;
    }

    @Override
    public void checkAttrIfBindingEnum(BigInteger classOid, String classType) {
        List<TyAttributeDefMapVO> tyAttributeDefMapVOS = typlmTypeService.queryInheritAttrDef(classOid, classType);
        List<TyAttributeDefMapVO> filter = tyAttributeDefMapVOS.stream().filter(item -> item.getName().startsWith("enum"))
                .collect(Collectors.toList());
        if(CollUtil.isNotEmpty(filter)){
            List<TyplmConstraintQueryDTO> list = new ArrayList<>();
            for (TyAttributeDefMapVO tyAttributeDefMapVO : filter) {
                TyplmConstraintQueryDTO constraintQueryDTO = new TyplmConstraintQueryDTO();
                constraintQueryDTO.setAttributereferenceoid(tyAttributeDefMapVO.getOid());
                constraintQueryDTO.setAttributereferenceotype(tyAttributeDefMapVO.getOtype());
                list.add(constraintQueryDTO);
            }
            List<TyplmConstraintEditVO> entityConstraint = typlmConstraintExtService.getEntityConstraint(list);
            Map<String, List<TyplmConstraintEditVO>> constraintMap = entityConstraint.stream()
                    .collect(Collectors.groupingBy(TyplmConstraintEditVO::getAttributeoid));
            Map<BigInteger, TyAttributeDefMapVO> tyAttributeDefMap = filter.stream()
                    .collect(Collectors.toMap(TyAttributeDefMapVO::getOid, item -> item));
            List<String> notBindingEnumAttr = new ArrayList<>();
            for (String key : constraintMap.keySet()) {
                List<TyplmConstraintEditVO> constraintEditVOList = constraintMap.get(key);
                boolean isBinding = constraintEditVOList.stream()
                        .anyMatch(vo -> "EnumDiscreteSetConstraint".equals(vo.getKey()) && "0".equals(vo.getEnumoid()));
                boolean isBinding2 = constraintEditVOList.stream()
                        .anyMatch(vo -> "EnumDiscreteSetConstraint".equals(vo.getKey()));

                if(isBinding || !isBinding2){
                    TyAttributeDefMapVO tyAttributeDefMapVO = tyAttributeDefMap.get(new BigInteger(key));
                    notBindingEnumAttr.add(tyAttributeDefMapVO.getName());
                }
            }
            if(CollUtil.isNotEmpty(notBindingEnumAttr)){
                throw RTErrorCodeEnum.CLASSIFICATION_NOT_UNIQUE_ERROR.getException("属性：" + String.join(",", notBindingEnumAttr) + "未绑定枚举");
            }
        }
    }

    @Override
    public List<EnumerationValueDTO> selectEnumByPid(BigInteger pid) {

        return tyEnumerationdefMapper.selectEnumByPid(pid);
    }

    @Override
    @Transactional(rollbackFor = Exception.class ,propagation = Propagation.REQUIRED)
    public void updateEnumItem(List<EnumerationItemHandleVO> enumItemVOS, BigInteger parentEnumOid,
                               BigInteger attrLinkId, String childEnumOid, boolean isParent) {
        HandleEnumItemDTO handleEnumItemDTO = new HandleEnumItemDTO();
        handleEnumItemDTO.setEnumItemList(enumItemVOS);
        handleEnumItemDTO.setDefoid(new BigInteger(childEnumOid));
        typlmEnumerationService.handleEnumItemList(handleEnumItemDTO);
        //查询枚举是否存在
        if (!isParent) {
            log.info("enumItemVOS =====> : {}",enumItemVOS.size());
            String description =enumItemVOS.stream().map(EnumerationItemHandleVO::getName).sorted().collect(Collectors.joining(""));
            JSONObject enumLinkData = rtEnumMapper.select(String.valueOf(attrLinkId));
            if(ObjectUtil.isNotEmpty(enumLinkData)){
                rtEnumMapper.delete(String.valueOf(attrLinkId));
            }
            rtEnumMapper.insertEnumDescription(childEnumOid, description, String.valueOf(attrLinkId),
                                               String.valueOf(parentEnumOid));
        }
    }
}




